using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Web.Routing;
using System.Web.Security;
using System.IO;

using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId.RelyingParty;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;

using DomainModel.Entities;
using DomainModel.Concrete;
using WebCore.Caching;
using WebCore;
using WebCore.Helpers;
using WebCore.Attributes;

#region OpenID 

//TODO: 

//http://www.west-wind.com/Weblog/posts/899303.aspx
//http://dotnetopenauth.net:8000/wiki/CodeSnippets/OpenIDRP/Programmatic
//http://stackoverflow.com/questions/1593506/dotnetopenid-open-id-get-some-data

// yahoo
//http://blog.nerdbank.net/2008/06/why-yahoo-says-your-openid-site.html
#endregion




namespace WebController.Controllers
{
    public class UserController : _baseController
    {
        UsersRepository _usersRepository = null;

        public UserController()
        {
            _usersRepository = new UsersRepository();
        }

        #region Login and LogOut

        public ActionResult Index()
        {
            return View();
        }


        public ActionResult Login(string returnURL)
        {

            using (var openid = new OpenIdRelyingParty())
            {
                IAuthenticationResponse response = openid.GetResponse();

                if (response != null)
                {
                    switch (response.Status)
                    {
                        case AuthenticationStatus.Authenticated:
                            FormsAuthentication.RedirectFromLoginPage(response.ClaimedIdentifier, false);

                            var res = response.GetUntrustedExtension<ClaimsResponse>();
                            string openIDStr = response.ClaimedIdentifier.ToString();

                            LoadOrAddUser(res, openIDStr);
                            UserHelper.IssueAuthTicket(_user, true);
                            break;


                        case AuthenticationStatus.Canceled:
                            ModelState.AddModelError("loginIdentifier",
                                "Login was cancelled at the provider");
                            break;

                        case AuthenticationStatus.Failed:
                            ModelState.AddModelError("loginIdentifier",
                                "Login failed using the provided OpenID identifier");
                            break;
                    }
                }

                if (response != null && response.Status == AuthenticationStatus.Authenticated)
                {
                    // user need to update their name if is default or empty
                    if (_user.Name.Equals(UserHelper.initialName, StringComparison.InvariantCultureIgnoreCase) || string.IsNullOrEmpty(_user.Name))
                    {
                        return RedirectToAction("UserEdit", new { userID = _user.UserID });
                    }
                    // TODO: set the return URL 
                    // http://stackoverflow.com/questions/332603/mvc-and-openid-redirection-problems
                    // http://www.codeplex.com/blogsvc/SourceControl/changeset/view/31628#392049
                    return ReturnURL(returnURL);
                    
                }
                else
                {
                    return View();

                }
            }

           

        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Login(FormCollection form)
        {
            //loginIdentifier = "https://www.google.com/accounts/o8/id";

            string loginIdentifier = form["url"];

            if (!Identifier.IsValid(loginIdentifier))
            {
                ModelState.AddModelError("loginIdentifier",
                            "The specified login identifier is invalid");
                return View();
            }
            else
            {
                using (var openid = new OpenIdRelyingParty())
                {
                    IAuthenticationRequest request = openid.CreateRequest(
                        Identifier.Parse(loginIdentifier));

                    // Require some additional data
                    request.AddExtension(new ClaimsRequest
                    {
                        BirthDate = DemandLevel.Request,
                        Country = DemandLevel.Request,
                        Email = DemandLevel.Require,
                        FullName = DemandLevel.Request,
                        Gender = DemandLevel.Request,
                        Language = DemandLevel.Request,
                        Nickname = DemandLevel.Request,
                        PostalCode = DemandLevel.Request,
                        TimeZone = DemandLevel.Request
                    });

                    return request.RedirectingResponse.AsActionResult();
                }
            }
        }

        public ActionResult LogOut(string userID, string returnURL)
        { 
            // remove cache
            string key = string.Format(Settings.Cache_User_OpenID_Key, userID);
            WebCache.Remove(key);

            FormsAuthentication.SignOut();

            return ReturnURL(returnURL);
            
        }

        private void LoadOrAddUser(ClaimsResponse res, string openIDStr)
        {
            _user.OpenID = openIDStr;
            _user.Name = string.IsNullOrEmpty(res.Nickname) ? UserHelper.initialName : res.Nickname;
            _user.RealName = res.FullName;
            _user.Email = res.Email;

            var user = _usersRepository.GetByOpenID(openIDStr);

            // user is not exist, then we add one
            if (user == null)
            {
                var now = DateTime.Now;
                _user.DateUpdated = now;
                _user.DateLastLogin = now;
                _user.LoginTimes = 1;
                _user.UserRole = "User";
                _user.About = "Unkown";
                _user.ImageName = UserHelper.GetUserTempImage();  //save a temp image for user

                _usersRepository.Save(_user); // save data
            }
            else
            {
                _user = user;
            }

        }

        #endregion

        #region User Image Handeling

        [AcceptVerbs(HttpVerbs.Post)]
        [CustomAuthorize(Roles = WebRoles.User | WebRoles.Admin)]
        public ActionResult ImageUpload(HttpPostedFileBase myImage)
        {


            if (myImage == null)
            {
                ViewData["ErrorMessage"] = "Please select a file";
                return View();
            }
            else
            {
                string fileName = Path.GetFileName(myImage.FileName).ToLower();

                // check file size
                if (myImage.ContentLength > 3179394)
                {
                    ViewData["ErrorMessage"] = "File should less then 3m";
                    return View();
                }//check the file type
                else if (!fileName.EndsWith(".jpg") && !fileName.EndsWith(".png") && !fileName.EndsWith(".gif"))
                {
                    ViewData["ErrorMessage"] = "File should be .jpg, .png or .gif";
                    return View();
                }

                // upload file
                string filePath = FileHelper.UploadFileToSever(myImage, Settings.UserImageTempPath);
           
                string newFileName = "_" + fileName;
                // resize image and over rewrite the original one
                string newFilePath = Path.Combine(Server.MapPath(Settings.UserImageTempPath), newFileName);

                ImageHelper.ResizeImage(filePath, newFilePath, 800, false);

                // delete the orginal file
                FileHelper.DeleteFile(filePath);

                // new image info for preview image
                ViewData["newFileDetails"] = ImageHelper.GetImageInfo(newFilePath);
                ViewData["newFileURL"] = (Settings.UserImageTempPath.Replace("~", string.Empty) + newFileName);

                return View("ImageCrop");
            }
        }

        [AcceptVerbs(HttpVerbs.Post)]
        [CustomAuthorize(Roles = WebRoles.User | WebRoles.Admin)]
        public ActionResult ImageCrop(FormCollection myform)
        {

            //TODO: Add validation
            int X1 = Convert.ToInt32(myform["x1"]);
            int Y1 = Convert.ToInt32(myform["y1"]);
            int X2 = Convert.ToInt32(myform["x2"]);
            int Y2 = Convert.ToInt32(myform["y2"]);
            int X = System.Math.Min(X1, X2);
            int Y = System.Math.Min(Y1, Y2);
            int w = Convert.ToInt32(myform["w"]);
            int h = Convert.ToInt32(myform["h"]);

            // That can be any image type (jpg,jpeg,png,gif) from any where in the local server
            string originalFile = Server.MapPath(myform["newFileURL"]);

            string fileName = ImageHelper.CropImage(X, Y, w, h, originalFile, Server.MapPath(Settings.UserImageTempPath), 100L);

            string fileUserCroppedPath = Server.MapPath(Settings.UserImageTempPath) + fileName; // for resize to 128px


            //image resize
            ImageHelper.ResizeImage(fileUserCroppedPath, Server.MapPath(Settings.UserImagePath) + fileName, 128, true);

            // delete the file
            FileHelper.DeleteFile(originalFile);
            FileHelper.DeleteFile(fileUserCroppedPath);// deleted user cropped file

            // delete the current image which is in using
            string currentFilePath = string.Concat(Server.MapPath(string.Concat(Settings.UserImagePath, _user.ImageName)));
            if(!_user.ImageName.StartsWith(Settings.UserTempImageNamePattern))
                FileHelper.DeleteFile(currentFilePath);

            // save image for user
            _user.ImageName = fileName;
            _usersRepository.Merge(_user);

            return RedirectToAction("userEdit", "User", new { userID = _user.UserID});


        }


        [AcceptVerbs(HttpVerbs.Get)]
        [CustomAuthorize(Roles = WebRoles.User | WebRoles.Admin)]
        public ActionResult ImageUpload()
        {
            return View();
        }

        #endregion

        #region EditUser and Update Images

        [AcceptVerbs(HttpVerbs.Get)]
        [CustomAuthorize(Roles = WebRoles.User | WebRoles.Admin)]
        public ActionResult UserEdit(int? userID)
        {
            int id = userID ?? -1;

            if (!UserHelper.IsCreatedByUserID(id))
                return View("NotAuthenticatedUser");


            // no cache to reduce the work
            var webUser = _usersRepository.Get(id);

            // no usr found
            if (webUser == null)
                return RedirectToAction("Index", "Home");

            return View(webUser);
        }



        [AcceptVerbs(HttpVerbs.Post)]
        [CustomAuthorize(Roles = WebRoles.User | WebRoles.Admin)]
        public ActionResult UserEdit(User webUser)
        {
            if (!UserHelper.IsCreatedByUserID(webUser.UserID))
                return View("NotAuthenticatedUser");


            if (ModelState.IsValid)
            {
                webUser.Name = webUser.Name.Trim();
                webUser.Email = webUser.Email.Trim();
                webUser.About = webUser.About.Trim();
                webUser.DateUpdated = DateTime.Now;

                _usersRepository.Merge(webUser);

                // remove user cache
                string key = string.Format(Settings.Cache_User_ID_Key, webUser.UserID);
                WebCache.Remove(key);
                // if user update detail, user details in event cache need to be updated as well.
                EventHelper.RemoveAllEventCache();

                return RedirectToAction("index", "home");
            }
            else
            {
                // Validation error, so redisplay same view
                return View(webUser);
            }
        }


   

        #endregion


        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Details(int? id)
        {
            id = id ?? -1;

            string key = string.Format(Settings.Cache_User_ID_Key, id);

            var userObject = WebCache.Get(key);

            if (Settings.CacheEnabled && userObject != null)
            {
                return View((User)userObject);
            }

            var webUser = _usersRepository.Get(id);

            // no usr found
            if (webUser == null)
                return View("UserNotFound");

            // add cache
            WebCache.Add(key, webUser);

            return View(webUser);
        }

        private ActionResult ReturnURL(string returnURL)
        {
            if (!String.IsNullOrEmpty(returnURL))
            {
                return Redirect(returnURL);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }

    }

}
